package xrand

import (
	"encoding/hex"
	"math/rand/v2"
	"strconv"

	"gitee.com/gousing/helper/internal"
)

type RandomType int

const (
	RandomTypeDefault RandomType = iota // 默认随机字符字典(数字大小写字符)
	RandomTypeHex                       // 16进制随机字符字典(小写)
	RandomTypeCaptcha                   // 验证码随机字符字典(排除0/1/2/l/o/z等容易混淆的字符)
	RandomTypePasswd                    // 密码随机字符字典(包含大小写字母、数字、特殊符号)
)

const (
	rsDefaultTable = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"             // 默认随机字符字典
	rsHexTable     = "0123456789abcdef"                                                           // 随机16进制字符字典
	rsCaptchaTable = "3456789abcdefghjkmnprstuvwxyABCDEFGHJKMNPQRSTUVWXY"                         // 验证码字符字典（排除0/1/2/l/o/z等容易混淆的字符）
	rsPasswdTable  = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_" // 随机密码字符(包含大小写字母、数字、特殊符号)
)

//  ----------------
//  缓存内置字典的Mask掩码位数计算结果
//  ----------------
//  注意: 如修改字典，需通过 getTableMask(tableLenth) 重新获取Mask掩码位数计算结果
//  请通过 TestRandomMask()测试获取结果
//  ----------------
//  rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
// 	tableLenth:62 maskBits: 6, maskVal: 63, maskMax: 10
//  ----------------
//  rsHexTable : 0123456789abcdef
// 	tableLenth:16 maskBits: 5, maskVal: 31, maskMax: 12
//  ----------------
//  rsCaptchaTable : 3456789abcdefghjkmnprstuvwxyABCDEFGHJKMNPQRSTUVWXY
// 	tableLenth:50 maskBits: 6, maskVal: 63, maskMax: 10
//  ----------------
//  rsPasswdTable : 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_
// 	tableLenth:74 maskBits: 7, maskVal: 127, maskMax: 9

// Bytes 使用默认字典生成指定长度的字节切片
//   - 默认随机字典(数字大小写字符)
//   - rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
func Bytes(length int) []byte {
	if length < 1 {
		return []byte{}
	}
	//rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
	//tableLenth:62 maskBits: 6, maskVal: 63, maskMax: 10
	return getRandomBytes(length, rsDefaultTable, 62, 6, 63, 10, false)
}

// BytesWith 使用自定义字典生成指定长度的字节切片
//   - 自定义字典长度不能小于2
func BytesWith(length int, tableChar string) []byte {
	tableLenth := len(tableChar)
	if length < 1 || tableLenth < 2 {
		return []byte{}
	}
	// 依据字典长度获取掩码位数
	maskBits, maskVal, maskMax := getRandomTableMask(tableLenth)
	return getRandomBytes(length, tableChar, uint64(tableLenth), maskBits, maskVal, maskMax, false)
}

// String 随机生成指定长度的字符串
//   - 默认随机字典(数字大小写字符)
//   - rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
func String(length int) string {
	if length < 1 {
		return ""
	}
	//rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
	//tableLenth:62 maskBits: 6, maskVal: 63, maskMax: 10
	return getRandomString(length, rsDefaultTable, 62, 6, 63, 10, false)
}

// StringWith 使用自定义字典生成指定长度的字符串
//   - 自定义字典长度不能小于2
func StringWith(length int, tableChar string) string {
	tableLenth := len(tableChar)
	if length < 1 || tableLenth < 2 {
		return ""
	}
	// 依据字典长度获取掩码位数
	maskBits, maskVal, maskMax := getRandomTableMask(tableLenth)
	return getRandomString(length, tableChar, uint64(tableLenth), maskBits, maskVal, maskMax, false)
}

// CaptchaString 随机生成指定长度的 [ 验证码 ] 字符串
//   - 验证码字符字典（排除0/1/2/l/o/z等容易混淆的字符）
//   - rsCaptchaTable = "3456789abcdefghjkmnprstuvwxyABCDEFGHJKMNPQRSTUVWXY"
func CaptchaString(length int) string {
	if length < 1 {
		return ""
	}
	//
	// rsCaptchaTable : 3456789abcdefghjkmnprstuvwxyABCDEFGHJKMNPQRSTUVWXY
	// tableLenth:50 maskBits: 6, maskVal: 63, maskMax: 10
	return getRandomString(length, rsCaptchaTable, 50, 6, 63, 10, false)
}

// CaptchaBytes 随机生成指定长度的 [ 验证码 ] 字符串(字节切片)
func CaptchaBytes(length int) []byte {
	if length < 1 {
		return []byte{}
	}
	//
	// rsCaptchaTable : 3456789abcdefghjkmnprstuvwxyABCDEFGHJKMNPQRSTUVWXY
	// tableLenth:50 maskBits: 6, maskVal: 63, maskMax: 10
	return getRandomBytes(length, rsCaptchaTable, 50, 6, 63, 10, false)
}

// HexString 随机生成Hex16进制字符类型指定长度的字符串
//   - 注意: 指定长度必须为偶数, 如长度为奇数自动加1处理
//   - 默认随机字典(数字大小写字符)
//   - rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
func HexString(length int) string {
	if length < 1 {
		return ""
	}
	if length%2 != 0 {
		length++
	}
	//rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
	//tableLenth:62 maskBits: 6, maskVal: 63, maskMax: 10
	b := getRandomBytes(length, rsDefaultTable, 62, 6, 63, 10, false)
	dst := make([]byte, length*2)
	hex.Encode(dst, b)
	return internal.BytesToString(dst[:length])
}

// HexBytes 随机生成Hex16进制字符类型指定长度的字节切片
//   - 注意: 指定长度必须为偶数, 如长度为奇数自动加1处理
//   - 默认随机字典(数字大小写字符)
//   - rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
func HexBytes(length int) []byte {
	if length < 1 {
		return []byte{}
	}
	//rsDefaultTable: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
	//tableLenth:62 maskBits: 6, maskVal: 63, maskMax: 10
	b := getRandomBytes(length, rsDefaultTable, 62, 6, 63, 10, false)
	dst := make([]byte, length*2)
	hex.Encode(dst, b)
	return dst[:length]
}

// PasswdString 随机生成密码口令指定长度的字符串
//   - 使用随机密码字典(包含大小写字母、数字、特殊符号)
//   - rsPasswdTable : 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_
func PasswdString(length int) string {
	if length < 1 {
		return ""
	}
	//rsPasswdTable : 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_
	//tableLenth:74 maskBits: 7, maskVal: 127, maskMax: 9
	return getRandomString(length, rsPasswdTable, 74, 7, 127, 9, false)
}

// PasswdBytes 随机生成密码口令指定长度的字符串(字节切片)
func PasswdBytes(length int) []byte {
	if length < 1 {
		return []byte{}
	}
	//rsPasswdTable : 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~!@#$%^&*()_
	//tableLenth:74 maskBits: 7, maskVal: 127, maskMax: 9
	return getRandomBytes(length, rsPasswdTable, 74, 7, 127, 9, false)
}

// getRandomBytes 随机生成指定长度的字节切片
//
//go:noinline
func getRandomBytes(length int, tableChar string, tableLenth uint64, maskBits uint, maskVal uint64, maskMax uint, firstNotZero bool) []byte {
	randomBytes := make([]byte, length)
	for i, cache, next := length-1, rand.Uint64(), maskMax; i >= 0; {
		if next == 0 {
			cache, next = rand.Uint64(), maskMax
		}
		if idx := cache & maskVal; idx < tableLenth {
			if firstNotZero && i == length-1 && tableChar[idx] == '0' {
				cache >>= maskBits
				next--
				continue
			}
			randomBytes[i] = tableChar[idx]
			i--
		}
		cache >>= maskBits
		next--
	}
	return randomBytes
}

// getRandomString 随机生成指定长度的字符串
//
//go:noinline
func getRandomString(length int, tableChar string, tableLenth uint64, maskBits uint, maskVal uint64, maskMax uint, firstNotZero bool) string {
	randomBytes := make([]byte, length)
	for i, cache, next := length-1, rand.Uint64(), maskMax; i >= 0; {
		if next == 0 {
			cache, next = rand.Uint64(), maskMax
		}
		if idx := cache & maskVal; idx < tableLenth {
			if firstNotZero && i == length-1 && tableChar[idx] == '0' {
				cache >>= maskBits
				next--
				continue
			}
			randomBytes[i] = tableChar[idx]
			i--
		}
		cache >>= maskBits
		next--
	}
	return internal.BytesToString(randomBytes)
}

// getRandomTableMask 依据字典长度获取掩码位数
//
//go:noinline
func getRandomTableMask(tableLenth int) (maskBits uint, maskVal uint64, maskMax uint) {
	if tableLenth < 1 {
		return
	}
	maskBits = getRandomBase2Bits(tableLenth)
	maskVal = 1<<maskBits - 1
	maskMax = 63 / maskBits
	return
}

// getRandomBase2Bits 取得一个十进制数的二进制表示时的位数(长度)
//
//go:noinline
func getRandomBase2Bits(length int) uint {
	if length < 1 {
		return 0
	}
	return uint(len(strconv.FormatUint(uint64(length), 2)))
}
